import Mock from "mockjs";
import {
  proxy,
  XhrRequestConfig,
  XhrRequestHandler,
  XhrResponse,
  unProxy
} from "ajax-hook";
import Compose, { Middleware } from "./Compose";
import Context from "./Context";

export default class Yssoa {
  private static _instance: Yssoa;

  // 实现一个中间件组件可以增加中间件
  private middleware: Middleware<Context>[] = [];

  private constructor() {
    // 移除由于导入 mock 导致的 XHR 被代理问题
    console.log("成功导入 Mock V:" + Mock.version);
    Yssoa.unRegisterMock();
  }

  public static instance(): Yssoa {
    if (!Yssoa._instance) {
      Yssoa._instance = new Yssoa();
    }
    return Yssoa._instance;
  }

  public use(middleware: Middleware<Context>) {
    this.middleware.push(middleware);
  }

  public startProxy() {
    console.log("启动 ajax-hook");
    proxy({
      onRequest: this.callBack(),
      onError: (err, handler) => {
        handler.next(err);
      },
      onResponse: (response, handler) => {
        handler.next(response);
      }
    });
  }

  public stopProxy() {
    console.log("停止 ajax-hook");
    unProxy();
  }

  private static unRegisterMock() {
    if (window._XMLHttpRequest) {
      // mock代理，重置原生ajax对象
      window.XMLHttpRequest = window._XMLHttpRequest;
    }
  }

  private callBack() {
    const _app = this;
    const _handle = Compose<Context>(_app.middleware);
    return async (config: XhrRequestConfig, handler: XhrRequestHandler) => {
      const _res: XhrResponse = {
        config: config,
        status: 500,
        headers: { "content-type": "application/json" },
        response: null
      };

      const _ctx = new Context(config, _res, _app);

      await _handle(_ctx).then(() => {
        if (_ctx.hasError) {
          handler.reject(_ctx.err);
        } else if (!_ctx.matched) {
          handler.next(config);
        } else {
          handler.resolve(_ctx.res);
        }
      });
    };
  }
}
